home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / tabdlg2.zip / SRC / TABDLG.C < prev    next >
C/C++ Source or Header  |  1994-05-17  |  23KB  |  1,098 lines

  1. /*
  2. ** TabDlg DLL
  3. ** Copyright (c) 1994 Edward McCreary.
  4. ** All rights reserved.
  5. **
  6. ** Redistribution and use in source and binary forms are freely permitted
  7. ** provided that the above copyright notice and attibution and date of work
  8. ** and this paragraph are duplicated in all such forms.
  9. ** THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
  10. ** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  11. ** WARRANTIES OF MERCHANTIBILILTY AND FITNESS FOR A PARTICULAR PURPOSE.
  12. */
  13.  
  14. #define STRICT
  15. #include <windows.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include "tabdlg2.h"
  19. #include "common.h"
  20. #include "dyndlg.h"
  21.  
  22. static HINSTANCE hInst;    /* instance handle of the dll */
  23.  
  24. /*
  25. ** store tab data here, 
  26. ** referenced by dialog handle
  27. */
  28. static FRAME_ENTRY entries[MAX_ENTRY];                                        
  29.  
  30. static int nNextEntry = 0;     /* next empty entry */
  31.  
  32. /* height of tab */
  33. #define TAB_HEIGHT  20
  34.  
  35. /* pens used to draw with */
  36. static  HPEN pens[3];
  37.  
  38. #define PEN_BLACK  0
  39. #define PEN_WHITE  1
  40. #define PEN_SHADOW 2 
  41.  
  42. /* font used for depressed tabs */
  43. HFONT hFont = NULL;
  44.  
  45. /*
  46. ** 
  47. ** Library Entry point
  48. **
  49. */
  50. BOOL WINAPI LibMain (HINSTANCE hInstance, WORD wDataSeg,
  51.        WORD wHeapSize, LPSTR lpszCmdLine)
  52. {
  53.  if(wHeapSize != 0)
  54.   UnlockData(0);
  55.  
  56.  /* store off dll instance handle */
  57.  hInst = hInstance;
  58.  
  59.  /* to keep the compiler from bitching */
  60.  wDataSeg = wDataSeg;
  61.  lpszCmdLine = lpszCmdLine;
  62.  
  63.  return TRUE;
  64. }
  65.  
  66. /*
  67. ** 
  68. ** Lookup tab structure by id of tab
  69. **
  70. */
  71. TAB_ENTRY __export *GetTabEntry(FRAME_ENTRY *pFrame,int nTabID)
  72. {
  73.  TAB_ENTRY *ptr;
  74.  
  75.  /* get list of tabs in this frame */
  76.  ptr = pFrame->tab_list;
  77.  
  78.  /* while not end of list */
  79.  while(ptr)
  80.  {
  81.   if(ptr->nTabID == nTabID) /* if id's match, return pointer to tab */
  82.    return ptr;
  83.   
  84.   /* walk down list */
  85.   ptr = ptr->next; 
  86.  }
  87.  
  88.  /* return null if tab not found */
  89.  return NULL;
  90.  
  91. /*
  92. ** 
  93. ** Lookup internal structure of frame given dialog handle
  94. **
  95. */
  96. FRAME_ENTRY __export *GetFrameEntry(HWND hDlg)
  97. {
  98.  static HWND hDlgCache = NULL;
  99.  static FRAME_ENTRY *pFrameCache = NULL; 
  100.  FRAME_ENTRY *pFrame = NULL;
  101.  int i;
  102.  
  103.  /* if cached */
  104.  if(hDlg == hDlgCache)
  105.   return pFrameCache;
  106.  
  107.  for(i = 0; i < nNextEntry; i++)
  108.   if(entries[i].hDlg == hDlg)
  109.   {
  110.     pFrame = &entries[i];
  111.     break;
  112.   }
  113.  hDlgCache = hDlg;
  114.  pFrameCache = pFrame;  
  115.  return pFrame;
  116. }
  117.  
  118. /*
  119. ** 
  120. ** Set tab nTabID to be the top tab
  121. **
  122. */
  123. BOOL WINAPI __export SetTopTab(HWND hDlg, int nTabID)
  124. {
  125.  FRAME_ENTRY *pFrame;
  126.  TAB_ENTRY   *pTab;
  127.  TAB_CTL     *pControl;
  128.  UINT        uFlags;
  129.  
  130.  /* get data for this frame */
  131.  pFrame = GetFrameEntry(hDlg);
  132.  
  133.  /* abort if not found */
  134.  if(!pFrame)
  135.   return FALSE;
  136.  
  137.  /* save id of new top tab */
  138.  pFrame->nTopTab = nTabID;
  139.  
  140.  /* common flags */
  141.  uFlags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSIZE | 
  142.     SWP_NOZORDER; 
  143.  
  144.  /* get pointer to list of tabs */   
  145.  pTab = pFrame->tab_list;
  146.  
  147.  /*
  148.  **
  149.  ** loop through list, hide or show each one, then do an invalidate rect 
  150.  ** and updatewindow to force repaint.  this is cleaner than using ShowWindow
  151.  ** for each control.
  152.  **
  153.  */
  154.  
  155.  /* while not at end of list */
  156.  while(pTab)
  157.  {
  158.   pControl = pTab->controls;   /* get pointer to list controls in this tab */
  159.   /* while not at end of list */
  160.   while(pControl) 
  161.   {
  162.    if(pTab->nTabID == nTabID)   /* if new top tab, show control */                       
  163.      SetWindowPos(GetDlgItem(pFrame->hDlg,pControl->wID),NULL,0,0,0,0,
  164.         uFlags | SWP_SHOWWINDOW);
  165.    else                         /* else hide him */
  166.      SetWindowPos(GetDlgItem(pFrame->hDlg,pControl->wID),NULL,0,0,0,0,
  167.         uFlags | SWP_HIDEWINDOW);
  168.    
  169.    /* get next control in list */
  170.    pControl = pControl->next;
  171.   }  
  172.   /* get next tab in list */
  173.   pTab = pTab->next;
  174.  } 
  175.  return TRUE;
  176. }
  177.  
  178. /*
  179. ** 
  180. ** get id of last tab in the frame list
  181. **
  182. */
  183. int __export GetLastTab(FRAME_ENTRY *pFrame)
  184. {
  185.  TAB_ENTRY *pTab;
  186.  
  187.  /* get point to list of tabs */
  188.  if(pFrame->tab_list)
  189.  {
  190.   /* walk to the end of the list */
  191.   pTab = pFrame->tab_list;
  192.   while(pTab->next)
  193.    pTab = pTab->next;
  194.   
  195.   /* return id */ 
  196.   return pTab->nTabID; 
  197.  }
  198.  /* return -1 if failed */
  199.  return -1;
  200. }
  201.  
  202. /*
  203. ** 
  204. ** detect if mouse hit a tab
  205. **
  206. */
  207. int TabHit(HWND hDlg,WORD x, WORD y)
  208. {
  209.  FRAME_ENTRY *pFrame;
  210.  TAB_ENTRY   *pTab;
  211.  int nWidth;
  212.  POINT  pt;
  213.  RECT   rc;
  214.  int    nFrameLeft; 
  215.  
  216.  /* get frame data for this dialog box */
  217.  pFrame = GetFrameEntry(hDlg);
  218.  
  219.  /* abort if not found */
  220.  if(!pFrame)
  221.   return -1;
  222.  
  223.  /* get rectangle of frame control */
  224.  GetWindowRect(pFrame->hWnd,&rc);
  225.  
  226.  /* convert to client coordinates (dialog client) */
  227.  pt.x = rc.left;
  228.  pt.y = rc.top;
  229.  ScreenToClient(pFrame->hDlg,&pt);
  230.  
  231.  /* bottom of hit rectangle is top of frame control */
  232.  rc.bottom = pt.y;
  233.  
  234.  /* top is TAB_HEIGHT above bottom */
  235.  rc.top = rc.bottom - TAB_HEIGHT; 
  236.  
  237.  /* store left edge of the frame */
  238.  rc.left = nFrameLeft = pt.x;
  239.  
  240.  pt.x = rc.right;
  241.  pt.y = rc.bottom;
  242.  ScreenToClient(pFrame->hDlg,&pt);
  243.  rc.right = pt.x;
  244.  
  245.  /* store point where mouse clicked */
  246.  pt.x = x;
  247.  pt.y = y;
  248.  
  249.  /* quick test, if not in rectangle above frame, no sense trying the
  250.  ** others
  251.  */
  252.  if(!PtInRect(&rc,pt))
  253.   return -1;
  254.    
  255.  /* get the width of one tab */
  256.  nWidth = GetTabWidth(pFrame);
  257.  
  258.  /* get pointer to list of tabs */
  259.  pTab = pFrame->tab_list;
  260.  
  261.  /* while not end of list */
  262.  while(pTab)
  263.  {
  264.   /* calc left edge of this tab */
  265.   rc.left = nFrameLeft + pTab->nTabID*nWidth;
  266.   
  267.   /* right edge is simple nWidth over from left edge */
  268.   rc.right = rc.left + nWidth;
  269.   
  270.   /* if hit, return id */
  271.   if(PtInRect(&rc,pt))
  272.    return pTab->nTabID;
  273.   
  274.   /* get next tab in list */
  275.   pTab = pTab->next;
  276.  } 
  277.  
  278.  /* return -1 if none hit */
  279.  return -1;
  280. }
  281.  
  282. /*
  283. ** 
  284. ** find the width of a tab
  285. **
  286. */
  287. int GetTabWidth(FRAME_ENTRY *pFrame)
  288. {
  289.  int    nNumTabs;
  290.  int    nWidth;
  291.  RECT   rc;
  292.  
  293.  /* if only one tab, don't want it to extend the
  294.  ** entire length, use 2 instead
  295.  */
  296.  nNumTabs = (pFrame->nNextTab < 2?2:pFrame->nNextTab);
  297.  /* get rectange of frame control */
  298.  GetWindowRect(pFrame->hWnd,&rc);
  299.  
  300.  /* width of a tab is width of frame divided by the number of tabs */
  301.  nWidth = (rc.right - rc.left)/nNumTabs;
  302.  
  303.  return nWidth;
  304. }
  305.  
  306. /*
  307. ** 
  308. ** First time registration
  309. **
  310. */
  311. void __export RegisterLibrary(void)
  312. {
  313.  LOGFONT logfont;
  314.  
  315.  /* store handles to pens used to draw tabs */
  316.  pens[PEN_BLACK] = (HPEN)GetStockObject(BLACK_PEN);
  317.  pens[PEN_WHITE] = (HPEN)GetStockObject(WHITE_PEN);
  318.  pens[PEN_SHADOW] = CreatePen(PS_SOLID,1,GetSysColor(COLOR_BTNSHADOW));
  319.  
  320.  /* create font used to draw depressed tab titles */
  321.  memset(&logfont,0,sizeof(LOGFONT));
  322.  logfont.lfHeight = -13; 
  323.  logfont.lfWeight = FW_NORMAL; 
  324.  lstrcpy(logfont.lfFaceName,"Arial");
  325.  
  326.  hFont = CreateFontIndirect(&logfont); 
  327.  /* if unable to create font, just use system font */
  328.  if(!hFont)
  329.   hFont = (HFONT)GetStockObject(SYSTEM_FONT);
  330. }
  331.  
  332. /*
  333. ** 
  334. ** Remove frame from list and free associated resources
  335. **
  336. */
  337. void __export UnRegisterFrame(HWND hWnd)
  338. {
  339.  int i,j;
  340.  TAB_ENTRY *ptr;
  341.  TAB_ENTRY *ptr_next;
  342.  
  343.  FRAME_ENTRY *pFrame = NULL;
  344.  
  345.  /* walk list of frames, find this one */
  346.  for(i = 0; i < nNextEntry; i++)
  347.   if(entries[i].hWnd == hWnd)
  348.   {
  349.    pFrame = &entries[i];
  350.    break;
  351.   } 
  352.  
  353.  /* if not found, abort */
  354.  if(!pFrame)
  355.   return;
  356.  
  357.  /* restore original window proc for frame */ 
  358.  SetWindowLong(hWnd,GWL_WNDPROC,
  359.   (DWORD)entries[i].OldWndProc);
  360.  
  361.  /* restore original window proc for dialog */
  362.  SetWindowLong(entries[i].hDlg,GWL_WNDPROC,
  363.   (DWORD)entries[i].OldDlgProc);
  364.  
  365.  /* walk list of tabs and free memory for each */
  366.  ptr = pFrame->tab_list;
  367.  while(ptr)
  368.  {
  369.   ptr_next = ptr->next;  
  370.   FreeTab(ptr);
  371.   ptr = ptr_next;  
  372.  }
  373.  
  374.  /* slide all entries above this one down one notch in list */
  375.  for(j = i; j < MAX_ENTRY; j++)
  376.   entries[j] = entries[j+1];
  377.   
  378.  /* decrement entry counter */
  379.  nNextEntry--;
  380.  
  381.  /* if none currently registered, free global resources */
  382.  if(nNextEntry == 0)
  383.   UnRegisterLibrary();
  384. }
  385.  
  386. /*
  387. ** 
  388. ** free up memory used with tab
  389. **
  390. */
  391. void FreeTab(TAB_ENTRY *pTab)
  392. {
  393.  TAB_CTL *ptr;
  394.  TAB_CTL *ptr_next;
  395.  
  396.  /* free memory used to store title */
  397.  free((void *)pTab->name);
  398.  
  399.  /* walk list of controls and free memory assoc. with each */
  400.  ptr = pTab->controls;
  401.  while(ptr)
  402.   {
  403.    ptr_next = ptr->next;
  404.    free((void *)ptr);
  405.    ptr = ptr_next;
  406.   }
  407.  
  408.  /* free tab memory */ 
  409.  free((void *)pTab);
  410. }
  411.  
  412. /*
  413. ** 
  414. ** last time deregistration
  415. **
  416. */
  417. void __export UnRegisterLibrary(void)
  418. {
  419.  DeleteObject(pens[PEN_SHADOW]);
  420.  DeleteObject(hFont);
  421. }
  422.  
  423. /*
  424. ** 
  425. ** force repaint of tabs
  426. **
  427. */
  428. void UpdateTabs(HWND hDlg)
  429. {
  430.  InvalidateRect(hDlg,NULL,TRUE);
  431.  UpdateWindow(hDlg);
  432. }
  433.  
  434. /*
  435. ** 
  436. ** paint the frame control
  437. **
  438. */
  439. void __export PaintFrame(FRAME_ENTRY *pFrame)
  440. {
  441.  RECT   rc;
  442.  POINT  pt[4];
  443.  HPEN   hOldPen;
  444.  HDC    hdc;
  445.  
  446.  /* get rect of frame control */
  447.  GetWindowRect(pFrame->hWnd,&rc);
  448.  
  449.  /* convert to client coordinates of dialog box */
  450.  pt[0].x = rc.left;
  451.  pt[0].y = rc.top;
  452.  ScreenToClient(pFrame->hDlg,&pt[0]);
  453.  rc.left = pt[0].x;
  454.  rc.top = pt[0].y;
  455.  
  456.  pt[0].x = rc.right;
  457.  pt[0].y = rc.bottom;
  458.  ScreenToClient(pFrame->hDlg,&pt[0]);
  459.  rc.right = pt[0].x;
  460.  rc.bottom = pt[0].y;
  461.  
  462.  /* get a dc to the dialog box */
  463.  hdc = GetDC(pFrame->hDlg);
  464.  
  465.  /* now draw the u shaped frame */
  466.  hOldPen = SelectObject(hdc, pens[PEN_BLACK]); 
  467.  // black frame
  468.  pt[0].x = rc.left;
  469.  pt[0].y = rc.top;
  470.  pt[1].x = rc.left;
  471.  pt[1].y = rc.bottom;
  472.  pt[2].x = rc.right;
  473.  pt[2].y = rc.bottom;
  474.  pt[3].x = rc.right;
  475.  pt[3].y = rc.top-1; // make sure they connect
  476.  
  477.  Polyline(hdc,(LPPOINT)&pt,4);
  478.  
  479.  SelectObject(hdc,pens[PEN_WHITE]);
  480.  // two white border lines
  481.  pt[0].x = rc.left+1;
  482.  pt[0].y = rc.top;
  483.  pt[1].x = rc.left+1;
  484.  pt[1].y = rc.bottom-1; 
  485.  
  486.  Polyline(hdc,(LPPOINT)&pt,2);
  487.  
  488.  pt[0].x = rc.left+2;
  489.  pt[0].y = rc.top;
  490.  pt[1].x = rc.left+2;
  491.  pt[1].y = rc.bottom-2;
  492.  Polyline(hdc,(LPPOINT)&pt,2);
  493.  
  494.  SelectObject(hdc,pens[PEN_SHADOW]); 
  495.  // two shadow lines
  496.  pt[0].x = rc.left + 1;
  497.  pt[0].y = rc.bottom - 1;
  498.  pt[1].x = rc.right-1;
  499.  pt[1].y = rc.bottom - 1;
  500.  pt[2].x = rc.right - 1;
  501.  pt[2].y = rc.top - 1;
  502.  
  503.  Polyline(hdc,(LPPOINT)&pt,3);
  504.  
  505.  pt[0].x = rc.left + 2;
  506.  pt[0].y = rc.bottom - 2;
  507.  pt[1].x = rc.right-2;
  508.  pt[1].y = rc.bottom - 2;
  509.  pt[2].x = rc.right - 2;
  510.  pt[2].y = rc.top - 1;
  511.  Polyline(hdc,(LPPOINT)&pt,3);
  512.  
  513.  /* restore old pen */   
  514.  SelectObject(hdc,hOldPen);   
  515.  
  516.  /* paint tabs above the frame */
  517.  PaintTabs(pFrame,hdc,&rc); 
  518.  
  519.  /* give dc back to system */
  520.  ReleaseDC(pFrame->hDlg,hdc); 
  521. }
  522.  
  523. /*
  524. ** 
  525. ** draw the tabs on top of the frame
  526. **
  527. */
  528. void __export PaintTabs(FRAME_ENTRY *pFrame,HDC hdc,LPRECT lprc)
  529. {
  530.  RECT   rcTab;
  531.  int    nWidth; 
  532.  TAB_ENTRY  *pTab;
  533.  int    nFrameLeft;
  534.  int    nLastTab;
  535.  POINT  pt[6];
  536.  HPEN   hOldPen;
  537.  
  538.  /* store left edge of frame */
  539.  nFrameLeft = lprc->left;
  540.  
  541.  /* set top and bottom limits of tabs */
  542.  rcTab.bottom = lprc->top;
  543.  rcTab.top = rcTab.bottom - TAB_HEIGHT; 
  544.  
  545.  /* get width of single tab */
  546.  nWidth = GetTabWidth(pFrame);
  547.  
  548.  /* index of last tab in list */
  549.  nLastTab = GetLastTab(pFrame);
  550.  
  551.  /* paint each tab */
  552.  pTab = pFrame->tab_list;
  553.  while(pTab)
  554.  {
  555.   /* set left and right limits of this tab */
  556.   rcTab.left = nFrameLeft + pTab->nTabID*nWidth;
  557.   rcTab.right = rcTab.left + nWidth;
  558.   
  559.   // if last tab, expand rect to end of frame
  560.   // but not if last tab == first tab
  561.   if(pTab->nTabID != 0 && pTab->nTabID == nLastTab)
  562.    rcTab.right = lprc->right;   
  563.   
  564.   /* if tab is top tab, draw it in up position */ 
  565.   if(pFrame->nTopTab == pTab->nTabID)
  566.   {
  567.    PaintUpTab(hdc,&rcTab);
  568.    DrawTabText(hdc,&rcTab,(LPCSTR)pTab->name,TRUE,pFrame->bUseShadow);
  569.    if(GetFocus() == pFrame->hWnd) 
  570.     DrawFocusRect(hdc,&rcTab);
  571.   
  572.   }
  573.   else
  574.   /* draw in down position */
  575.   {
  576.    PaintDownTab(hdc,&rcTab);
  577.    DrawTabText(hdc,&rcTab,(LPCSTR)pTab->name,FALSE,pFrame->bUseShadow);   
  578.   }  
  579.   /* loop to next tab in list */
  580.   pTab = pTab->next;
  581.  }
  582.  
  583.  /* draw horz lines */ 
  584.  /* this make lower tabs appear below top tab */
  585.  
  586.  /*
  587.  ** if top tab not first in list, draw lines from left edge of
  588.  ** frame to left edge of top tab
  589.  */
  590.  if(pFrame->nTopTab != 0) 
  591.  {
  592.   hOldPen = SelectObject(hdc,pens[PEN_BLACK]);
  593.   pt[0].x = lprc->left+1;
  594.   pt[0].y = lprc->top;
  595.   pt[1].x = pFrame->nTopTab*nWidth + nFrameLeft;
  596.   pt[1].y = lprc->top;
  597.   Polyline(hdc,(LPPOINT)&pt,2); 
  598.   
  599.   SelectObject(hdc,pens[PEN_WHITE]);
  600.   pt[1].x = pFrame->nTopTab*nWidth + nFrameLeft + 3;
  601.   pt[0].y = lprc->top + 1;
  602.   pt[1].y = lprc->top + 1;
  603.   Polyline(hdc,(LPPOINT)&pt,2); 
  604.   pt[0].y = lprc->top + 2;
  605.   pt[1].y = lprc->top + 2;
  606.   Polyline(hdc,(LPPOINT)&pt,2); 
  607.   
  608.   SelectObject(hdc,hOldPen);
  609.  }
  610.  /* if not end of list or if only one tab */ 
  611.  
  612.  /*
  613.  ** draw lines from right edge of last tab to right edge
  614.  ** of frame
  615.  */
  616.  if(pFrame->nTopTab != nLastTab || nLastTab == 0) 
  617.  {
  618.   hOldPen = SelectObject(hdc,pens[PEN_BLACK]);
  619.   pt[0].x = pFrame->nTopTab*nWidth + nFrameLeft + nWidth;
  620.   pt[0].y = lprc->top;
  621.   pt[1].x = lprc->right;
  622.   pt[1].y = lprc->top;
  623.   Polyline(hdc,(LPPOINT)&pt,2); 
  624.   
  625.   SelectObject(hdc,pens[PEN_WHITE]);  
  626.   pt[0].y++;  
  627.   pt[1].y++;
  628.   Polyline(hdc,(LPPOINT)&pt,2); 
  629.  
  630.   pt[0].x--;
  631.   pt[0].y++;
  632.   pt[1].x--;
  633.   pt[1].y++;
  634.   Polyline(hdc,(LPPOINT)&pt,2); 
  635.   
  636.   SelectObject(hdc,pens[PEN_SHADOW]); 
  637.   pt[0].y--;
  638.   pt[1].y = pt[0].y;
  639.   pt[1].x = pt[0].x - 1;
  640.   pt[2].x = pt[1].x;
  641.   pt[2].y = pt[1].y + 2;
  642.   Polyline(hdc,(LPPOINT)&pt,3); 
  643.   
  644.   SelectObject(hdc,hOldPen);
  645.  }
  646. }
  647.  
  648. /*
  649. ** 
  650. ** draw the text in the tab
  651. **
  652. */
  653. void DrawTabText(HDC hdc,LPRECT lprc,LPCSTR text,BOOL bTop, BOOL bShadow)
  654. {
  655.  RECT       rc;
  656.  COLORREF   cwOld;
  657.  HFONT      hOldFont;
  658.  int        nOldBkMode;
  659.  UINT uTextStyle = DT_SINGLELINE | DT_VCENTER | DT_CENTER;
  660.  
  661.  /* let background color show */
  662.  nOldBkMode = SetBkMode(hdc,TRANSPARENT);
  663.  
  664.  /* don't screw up lprc */
  665.  CopyRect(&rc,lprc);
  666.  
  667.  /* to account for borders */
  668.  InflateRect(&rc,-5,-4);
  669.  
  670.  /* shift down and to the right */
  671.  OffsetRect(&rc,1,1);
  672.  
  673.  /* draw white text to give chisled look */
  674.  cwOld = SetTextColor(hdc,RGB(0xFF,0xFF,0xFF)); 
  675.  
  676.  /* use small font for depressed tabs */
  677.  if(!bTop)
  678.   hOldFont = SelectObject(hdc,hFont);
  679.  
  680.  if(bShadow) /* only draw if shadow enabled */
  681.   DrawText(hdc,text,-1,&rc,uTextStyle);
  682.  
  683.  /* shift up and to the right */
  684.  OffsetRect(&rc,-1,-1);
  685.  
  686.  /* use black text */
  687.  SetTextColor(hdc,RGB(0x00,0x00,0x00)); 
  688.  
  689.  DrawText(hdc,text,-1,&rc,uTextStyle); 
  690.  
  691.  /* restore original font if needed */
  692.  if(!bTop)
  693.   SelectObject(hdc,hOldFont);
  694.  
  695.  /* restore old text color */
  696.  SetTextColor(hdc,cwOld);
  697.  
  698.  /* restore old background mode */
  699.  SetBkMode(hdc,nOldBkMode);
  700. }
  701.  
  702. /*
  703. ** 
  704. ** draw a top tab
  705. **
  706. */
  707. void __export PaintUpTab(HDC hdc, LPRECT lprc)
  708. {
  709.  POINT  pt[6];
  710.  HPEN   hOldPen;
  711.  
  712.  /* top tab is just the down tab with some extra lines */
  713.  PaintDownTab(hdc,lprc);
  714.  hOldPen = SelectObject(hdc,pens[PEN_WHITE]);
  715.  
  716.  pt[0].x = lprc->left + 2;
  717.  pt[0].y = lprc->bottom;
  718.  
  719.  pt[1].x = lprc->left + 2;
  720.  pt[1].y = lprc->top + 4;
  721.  
  722.  pt[2].x = lprc->left + 4;
  723.  pt[2].y = lprc->top + 2;
  724.  
  725.  pt[3].x = lprc->right - 4;
  726.  pt[3].y = lprc->top + 2;
  727.  
  728.  Polyline(hdc,(LPPOINT)&pt,4); 
  729.  
  730.  pt[0].x = lprc->left + 3;
  731.  pt[0].y = lprc->top + 4;
  732.  
  733.  pt[1].x = lprc->left + 5;
  734.  pt[1].y = lprc->top + 2;
  735.  
  736.  Polyline(hdc,(LPPOINT)&pt,2); 
  737.    
  738.  SelectObject(hdc,pens[PEN_SHADOW]); 
  739.  
  740.  pt[0].x = lprc->right - 4 ;
  741.  pt[0].y = lprc->top + 2;
  742.  
  743.  pt[1].x = lprc->right - 2;
  744.  pt[1].y = lprc->top + 4;
  745.  
  746.  pt[2].x = lprc->right - 2;
  747.  pt[2].y = lprc->bottom + 1;
  748.  
  749.  Polyline(hdc,(LPPOINT)&pt,3); 
  750.  
  751.  pt[0].x = lprc->right - 4 ;
  752.  pt[0].y = lprc->top + 3;
  753.  
  754.  pt[1].x = lprc->right - 2 ;
  755.  pt[1].y = lprc->top + 5;
  756.  
  757.  Polyline(hdc,(LPPOINT)&pt,2); 
  758.  
  759.  SelectObject(hdc,hOldPen);
  760. }
  761.  
  762. /*
  763. ** 
  764. ** draw a down tab
  765. **
  766. */
  767. void __export PaintDownTab(HDC hdc, LPRECT lprc)
  768. {
  769.  POINT  pt[6];
  770.  HPEN   hOldPen;
  771.  
  772.  hOldPen = SelectObject(hdc,pens[PEN_BLACK]);
  773.  
  774.  pt[0].x = lprc->left;
  775.  pt[0].y = lprc->bottom;
  776.  
  777.  pt[1].x = lprc->left;
  778.  pt[1].y = lprc->top + 4;
  779.  
  780.  pt[2].x = lprc->left + 4;
  781.  pt[2].y = lprc->top;
  782.  
  783.  pt[3].x = lprc->right - 4;
  784.  pt[3].y = lprc->top;
  785.  
  786.  pt[4].x = lprc->right;
  787.  pt[4].y = lprc->top + 4;
  788.  
  789.  pt[5].x = lprc->right;
  790.  pt[5].y = lprc->bottom;
  791.  
  792.  Polyline(hdc,(LPPOINT)&pt,6);
  793.  
  794.  SelectObject(hdc,pens[PEN_WHITE]);
  795.  
  796.  pt[0].x = lprc->left + 1;
  797.  pt[0].y = lprc->bottom;
  798.  
  799.  pt[1].x = lprc->left + 1;
  800.  pt[1].y = lprc->top + 4;
  801.  
  802.  pt[2].x = lprc->left + 4;
  803.  pt[2].y = lprc->top + 1;
  804.  
  805.  pt[3].x = lprc->right - 3;
  806.  pt[3].y = lprc->top + 1;
  807.  
  808.  Polyline(hdc,(LPPOINT)&pt,4);
  809.  
  810.  SelectObject(hdc,pens[PEN_SHADOW]); 
  811.  
  812.  pt[0].x = lprc->right - 3 ;
  813.  pt[0].y = lprc->top + 2;
  814.  
  815.  pt[1].x = lprc->right - 1;
  816.  pt[1].y = lprc->top + 4;
  817.  
  818.  pt[2].x = lprc->right - 1;
  819.  pt[2].y = lprc->bottom + 1;
  820.  
  821.  Polyline(hdc,(LPPOINT)&pt,3);
  822.     
  823.  SelectObject(hdc, hOldPen);
  824. }
  825.  
  826. /*
  827. ** 
  828. ** Subclass proc for frame window
  829. **
  830. */
  831. LONG WINAPI __export FrameWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  832. {
  833.  FRAME_ENTRY *pFrame = NULL;
  834.  
  835.  /* get frame data */
  836.  pFrame = GetFrameEntry(GetParent(hWnd));
  837.  
  838.  /* this frame doesn't have and data so use default proc */
  839.  if(!pFrame)
  840.   return DefWindowProc(hWnd,msg,wParam,lParam);
  841.  
  842.     
  843.  switch(msg)
  844.  {
  845.   case WM_PAINT:
  846.   {   
  847.    PAINTSTRUCT ps;
  848.    
  849.    BeginPaint(hWnd,&ps);
  850.    PaintFrame(pFrame);                      
  851.    EndPaint(hWnd,&ps);   
  852.    return 0L;
  853.   }
  854.   break;
  855.   
  856.   case WM_NCDESTROY:
  857.    /* remove frame data for this window */
  858.    UnRegisterFrame(hWnd);
  859.    return 0L;
  860.  }
  861.  
  862.  /* call original window procedure */
  863.  return CallWindowProc(pFrame->OldWndProc,hWnd,msg,wParam,lParam);
  864. }
  865.  
  866. /*
  867. ** 
  868. ** subclass proc for dialog box
  869. **
  870. */
  871. LONG WINAPI __export DlgWndProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  872. {
  873.  FRAME_ENTRY *pFrame = NULL;
  874.  
  875.  /* get frame data for this dialog box */
  876.  pFrame = GetFrameEntry(hDlg);
  877.  
  878.  /* if not data found, revert to default dialog proc */    
  879.  if(!pFrame)
  880.   return DefDlgProc(hDlg,msg,wParam,lParam);
  881.     
  882.  switch(msg)
  883.  {
  884.   case WM_LBUTTONDOWN:
  885.   {
  886.    int id;
  887.    
  888.    /* check button click */
  889.    id = TabHit(hDlg,LOWORD(lParam),HIWORD(lParam));
  890.    /* if not -1, then is id of tab clicked on */
  891.    if(id != -1)
  892.     { 
  893.      /* no sense repainting if not neccessary */   
  894.       if(pFrame->nTopTab != id)
  895.       {
  896.        SetTopTab(hDlg,id);
  897.        /* force repaint */
  898.        UpdateTabs(hDlg);    
  899.       }
  900.     }   
  901.   }
  902.   break;
  903.   default:
  904.   break;
  905.  }
  906.  
  907.  /* call original dialog proc */
  908.  return CallWindowProc(pFrame->OldDlgProc,hDlg,msg,wParam,lParam);
  909.  
  910. /*
  911. ** 
  912. ** not much here...
  913. **
  914. */
  915. int WINAPI _WEP(int nSystemExit)
  916. {
  917.  
  918.   return 1;
  919. }
  920.  
  921.  
  922. /*
  923. ** 
  924. ** Build tab control from list of dialog templates
  925. **
  926. */
  927.  
  928. BOOL WINAPI __export BuildTabs(HWND hDlg,HINSTANCE hInst, UINT wFrameID, 
  929.     const TAGTEMPLATE FAR *lpTemplates, int nNumTemplates)
  930. {
  931.  int i;
  932.  HWND       hWnd;
  933.  
  934.  /* if maxed out abort */
  935.  if(nNextEntry == MAX_ENTRY)
  936.   return FALSE;
  937.  
  938.  /* get handle to frame */ 
  939.  hWnd = GetDlgItem(hDlg,wFrameID);
  940.  
  941.  /* store handles */
  942.  entries[nNextEntry].hWnd = hWnd;
  943.  entries[nNextEntry].hDlg = hDlg;
  944.  
  945.  /* first time, define globals */ 
  946.  if(nNextEntry == 0)
  947.   RegisterLibrary();
  948.  
  949.  /* subclass the frame and store old wndproc */
  950.  entries[nNextEntry].OldWndProc = (WNDPROC)SetWindowLong(hWnd,
  951.                 GWL_WNDPROC,(DWORD)FrameWndProc);
  952.  
  953.  /* subclass the dialog and store old wndproc */               
  954.  entries[nNextEntry].OldDlgProc = (WNDPROC)SetWindowLong(hDlg,
  955.                 GWL_WNDPROC,(DWORD)DlgWndProc);
  956.  
  957.  /* clear everything out */
  958.  entries[nNextEntry].tab_list = NULL;
  959.  entries[nNextEntry].nTopTab = 0;
  960.  entries[nNextEntry].nNextTab = 0; 
  961.  entries[nNextEntry].bUseShadow = FALSE;
  962.  
  963.  
  964.  nNextEntry++;
  965.  
  966.  /* for each template create a tab */
  967.  for(i=0;i<nNumTemplates;i++) 
  968.   if(!CreateSingleTab(hDlg,hInst,wFrameID,
  969.     (TAGTEMPLATE FAR *)&lpTemplates[i]))
  970.    return FALSE;
  971.  
  972.  /* set first one on top as default */
  973.  SetTopTab(hDlg,0);
  974.  return TRUE;
  975. }
  976.  
  977. /*
  978. ** 
  979. ** create a single tab from template
  980. **
  981. */
  982.  
  983. BOOL WINAPI CreateSingleTab(HWND hDlg,HINSTANCE hInst, UINT wFrameID, 
  984.     TAGTEMPLATE FAR *lpTemplate)
  985. {
  986.  FRAME_ENTRY *pFrame;
  987.  TAB_ENTRY   *pNewTab;
  988.  
  989.  /* pointer to info for this frame */
  990.  pFrame = GetFrameEntry(hDlg);
  991.  
  992.  /* abort! */
  993.  if(!pFrame)
  994.   return -1;
  995.  
  996.  /* alloc a new tab structure */ 
  997.  pNewTab = (TAB_ENTRY *)malloc(sizeof(TAB_ENTRY));
  998.  
  999.  /* abort */
  1000.  if(!pNewTab)
  1001.   return -1;
  1002.  
  1003.  /* alloc room for title and copy over */ 
  1004.  pNewTab->name = (char *)malloc(strlen(lpTemplate->lpTitle)+1);
  1005.  strcpy(pNewTab->name,lpTemplate->lpTitle);
  1006.  
  1007.  /* new tab id and clear out data */
  1008.  pNewTab->nTabID = pFrame->nNextTab++;
  1009.  pNewTab->controls = NULL;
  1010.  pNewTab->next = NULL;
  1011.  
  1012.  /* if tab_list empty, set new tab to first in list */
  1013.  if(pFrame->tab_list == NULL)
  1014.   pFrame->tab_list = pNewTab;
  1015.  else
  1016.  /* append to end of linked list */
  1017.  {
  1018.   TAB_ENTRY *ptr;
  1019.   
  1020.   ptr = pFrame->tab_list;
  1021.   
  1022.   while(ptr->next)
  1023.    ptr = ptr->next;
  1024.    
  1025.   ptr->next = pNewTab; 
  1026.  }
  1027.  
  1028.  /* create controls from template */
  1029.  return MergeControlsIntoDlg(hDlg,wFrameID,hInst,pNewTab,lpTemplate->lpDlgTemplate);
  1030. }
  1031.  
  1032. /*
  1033. ** 
  1034. ** add control to list of controls in pTab
  1035. **
  1036. */
  1037. BOOL WINAPI __export AddControl(TAB_ENTRY *pTab, WORD wControlID)
  1038. {
  1039.  TAB_CTL     *pCtl;
  1040.  
  1041.  if(!pTab)
  1042.   return FALSE;
  1043.  
  1044.  /* alloc new control structure and fill */ 
  1045.  pCtl = (TAB_CTL *)malloc(sizeof(TAB_CTL));
  1046.  
  1047.  /* abort if malloc failed */
  1048.  if(!pCtl)
  1049.   return FALSE;
  1050.  
  1051.  /* save control data */ 
  1052.  pCtl->wID = wControlID;
  1053.  pCtl->next = NULL;
  1054.  
  1055.  /* 
  1056.   * if list empty stick at the head otherwise append to the end
  1057.   * of the list.
  1058.   */
  1059.  if(pTab->controls == NULL)
  1060.   pTab->controls = pCtl;
  1061.  else
  1062.  {
  1063.   TAB_CTL *ptr;
  1064.   
  1065.   ptr = pTab->controls;
  1066.   
  1067.   while(ptr->next)
  1068.    ptr = ptr->next;
  1069.    
  1070.   ptr->next = pCtl; 
  1071.  }
  1072.  return TRUE;
  1073. }
  1074.  
  1075.  
  1076. /*
  1077. ** 
  1078. ** turn on/off shadow in tab's
  1079. **
  1080. */
  1081. void WINAPI __export SetTabStyle(HWND hDlg, DWORD dwStyle)
  1082. {
  1083.  FRAME_ENTRY *pFrame; 
  1084.  /* pointer to info for this frame */
  1085.  pFrame = GetFrameEntry(hDlg);
  1086.  
  1087.  /* abort! */
  1088.  if(!pFrame)
  1089.   return;
  1090.  
  1091.  if(dwStyle & TAB_SHADOWTEXT)
  1092.   pFrame->bUseShadow = TRUE; 
  1093.  else
  1094.   pFrame->bUseShadow = FALSE;
  1095. }
  1096.